package ar.cordoba.unc.famaf.pln.sashaNlgSystem;

import java.util.concurrent.BlockingQueue;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.atomic.AtomicBoolean;


/**
 * This Class allows to send to the subject string
 * messages ensuring that those are shown during the 
 * given time in ms.
 */
public class SenderThread extends Thread 
{
	private SashaNlgSystem system;
	private BlockingQueue<Message> toSendQueue;
	private boolean finished;
	private AtomicBoolean sending;
	private final static int DEFAULT_SEND_TIME = 5000;


	/**
	 * Creates a SenderThread class.
	 */
	public SenderThread(SashaNlgSystem system) 
	{
		this.system = system;
		this.toSendQueue = new LinkedBlockingQueue<Message>();
		this.finished = false;
		this.sending = new AtomicBoolean();
	}


	/**
	 * Represents an instruction message and contains
	 * the time in ms that the message should be shown
	 * to the DF.
	 */
	private class Message 
	{
		public String text;
		public int time;
		
		public Message(String text, int time)
		{
			this.text = text;
			this.time = time;
		}
	}


	/**
	 * Sends a text message to the subject.
	 * @param text: The message you want to send.
	 * @param time: The time you want to show the message in milliseconds.
	 */
	public void send(String text, int time) 
	{
		toSendQueue.add(new Message(text, time));
	}


	/**
	 * Shut down the sender thread.
	 */
	public void shutdown() 
	{
		finished = true;
		if (sending.compareAndSet(false, false))
			interrupt();
	}


	/**
	 * Clear the message queue. This will remove any unsent messages from the
	 * queue and ensure that the next message you send will be sent
	 * immediately.
	 */
	public void clear()
	{
		toSendQueue.clear();
		if (sending.compareAndSet(false, false))
			interrupt();
	}


	@Override
	public void run() 
	{
		while (!finished) 
		{
			try 
			{
				Message next = toSendQueue.take();
				int time = next.time;

	            int mod = time % DEFAULT_SEND_TIME;
	            if (mod > 0)
	            {
	            	sending.compareAndSet(false, true);
	            	system.send(next.text);
	            	sending.compareAndSet(true, false);
	            	sleep(mod);
	            	sending.compareAndSet(false, true);
	            	system.send("");
	            	sending.compareAndSet(true, false);
	            	time -= mod;
	            }
	            while (time > 0)
	            {
	            	sending.compareAndSet(false, true);
	            	system.send(next.text);
	            	sending.compareAndSet(true, false);
	            	sleep(DEFAULT_SEND_TIME);
	            	time -= DEFAULT_SEND_TIME;
	            }
			}
			catch (InterruptedException e)
			{
				if (finished)
					break;
	        }
	    }
		System.out.println("SenderThread Ended");
	}


	/**
	 * @return True is this thread has finished.
	 */
	public boolean isFinished() 
	{
		return finished;
	}

}
